
package in.kmb.inval;

import java.util.Random;

import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

/**
 * Activity illustrating an issue where a drawable which has had its bounds set,
 * reverts to its original bounds on orientation change.
 * 
 * @author Kiran Rao
 */
public class InvalidateDrawableActivity extends Activity {

    /*
     * Views representing Landscape and Portait orientations.
     */
    private View mLandscape, mPortrait;

    /**
     * Current config.
     */
    private Configuration mConfig;

    /*
     * Various Views to be manipulated.
     */
    private Button mBtn;
    private Drawable drContent;
    private ImageView ivContent;

    /**
     * Last known percentage height of the drawable.
     */
    private int mPercent;
    private Rect mBounds;
    private static final Rect EMPTY_BOUNDS = new Rect(0, 0, 0, 0);

    private Random mRandom = new Random();
    

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LayoutInflater li = LayoutInflater.from(this);

        /*
         * On creation, inflate the landscape and portrait layout XMLs onto
         * their respective views.
         */
        mPortrait = li.inflate(R.layout.portrait, null);
        mLandscape = li.inflate(R.layout.landscape, null);
    }

    @Override
    protected void onResume() {
        super.onResume();
        /*
         * On resume, check the current configuration, and setup accordingly.
         */
        mConfig = getResources().getConfiguration();
        setup();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        /*
         * We have set android:configChanges="orientation|keyboardHidden" in
         * manifest. Hence, this method is called on orientation change.
         * Activity is NOT recreated.
         */
        super.onConfigurationChanged(newConfig);

        /*
         * On orientation change, update the new config and setup accordingly.
         */
        this.mConfig = newConfig;
        setup();
    }

    /**
     * Sets up the views according to orientation.
     */
    private void setup() {
        if (Configuration.ORIENTATION_LANDSCAPE == mConfig.orientation) {
            displayLandscapeView();
        } else {
            displayPortraitView();
        }
    }

    /**
     * Displays the Landscape view.
     */
    private void displayLandscapeView() {
        setContentView(mLandscape);

    }

    /**
     * Displays the Portrait view and performs other initialization tasks.
     */
    private void displayPortraitView() {
       
        // First, set the content view to the portrait view.
        setContentView(mPortrait);
        
        // Initialize the various Views.
        if (ivContent == null) {
            ivContent = (ImageView) mPortrait.findViewById(R.id.imageView1);
        }

        if (drContent == null) {
            drContent = ivContent.getDrawable();
        }

        initBounds();

        if (mBtn == null) {
            mBtn = (Button) mPortrait.findViewById(R.id.button1);
        }

        ivContent.invalidate();
        
        
        /*
         * When button is clicked, update the drawable to a random height, which
         * is a percentage of its original height.
         */
        mBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                updateDrawable(mRandom.nextInt(100));
            }
        });
    }

    /**
     * Initialize the "reference" bounds. This is the bounds object used to
     * calculate the new bounds on update.
     */
    private void initBounds() {

        if (mBounds == null || EMPTY_BOUNDS.equals(mBounds)) {
            /*
             * We use copyBounds() because getBounds() may keep a reference to
             * the original object.
             */

            mBounds = drContent.copyBounds();
        }

    }

    /**
     * Updates the drawable to a new height, which is a percentage of its
     * original.
     * 
     * @param newPercent The new height as a percent of its original.
     */
    private void updateDrawable(int newPercent) {
        this.mPercent = newPercent;
        updateUi();
    }

    /**
     * Performs UI manipulation to update the height.
     */
    private void updateUi() {
        initBounds();

        Rect newBounds = new Rect(mBounds);
        newBounds.top = mBounds.bottom
                - (int) (this.mPercent * mBounds.height() / 100);

        drContent.setBounds(newBounds);
        ivContent.invalidate();

    }

}
